1.4.1 Always块(组合逻辑)
数字电路由逻辑门和连线组成,任何电路都可以通过模块和assign语句的某种组合来表达。然而,有时这并不是描述电路最方便的方式。过程(其中always块是一个例子)为描述电路提供了另一种语法。
对于硬件综合来说,有两种类型的always块是相关的:
- 组合逻辑:always @(*)
- 时钟控制:always @(posedge clk)
组合逻辑always块等同于assign语句,因此任何组合逻辑电路都可以用这两种方式中的任意一种来表达。选择使用哪一种主要取决于哪种语法更方便。过程块内的代码语法与外部代码不同。过程块拥有更丰富的语句集(如if-then、case),不能包含连续赋值,但也引入了许多非直观的错误方式。(*过程中的连续赋值确实存在,但与连续赋值略有不同,并且不可综合。)
例如,assign语句和组合逻辑always块描述的是同一个电路。两者都创建了相同的组合逻辑块。当任何输入(右侧)值变化时,两者都会重新计算输出。
assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;
对于组合逻辑always块,始终使用( * )作为敏感列表。显式列出信号容易出错(如果遗漏了一个),并且在硬件综合时会被忽略。如果你明确指定了敏感列表并遗漏了一个信号,综合出的硬件仍会表现得好像使用了( * ),但是仿真结果将不会匹配硬件的行为。(在SystemVerilog中,使用always_comb。)
关于wire与reg的一点说明:assign语句的左侧必须是网线类型(如wire),而在always块中的过程赋值(procedural assignment)左侧必须是变量类型(如reg)。这些类型(wire与reg)与综合出的硬件无关,只是Verilog作为硬件仿真语言使用时遗留下来的语法。
实践练习:
使用assign语句和组合逻辑always块各构建一个与门。(由于assign语句和组合逻辑always块功能相同,无法强制要求你同时使用两种方法。但你在这里是为了练习,对吧?...)
模块声明
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);